﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using VSDBM.Code.dao;
using VSDBM.Code.dto;
using VSDBM.Code.functions;
using System.Threading;
using System.Text;

public partial class Visual_Procedures_Mapping_SequenceMapping : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            FillOrganism();
        }
    }

    protected void FillOrganism()
    {
        DataSet ds = OrganismDAO.select("WHERE status=1", "ORDER BY name");
        //verifica erro na querry
        if (ds.Tables.Count == 0)
        {
            Exception ex = new Exception("Table not found!");
            throw ex;
        }
        //verifica se existem organismos cadastrados.
        else if (ds.Tables[0].Rows.Count == 0)
        {
            DataRow dr = ds.Tables[0].NewRow();
            ds.Tables[0].Rows.InsertAt(dr, 0);
            ds.Tables[0].Rows[0]["name"] = "NO ORGANISMS FOUND";
            ds.Tables[0].Rows[0]["id"] = "0";

        }
        //Insere os organismos no Dropdown List(ddOrganism).

        ddOrganism.DataSource = ds.Tables[0];
        ddOrganism.DataTextField = "name";
        ddOrganism.DataValueField = "id";
        ddOrganism.DataBind();

    }

    protected void btnRunMap_Click(object sender, EventArgs e)
    {
        //inicializa a variável dos parâmetros do mapeamento
        List<Object> parametros = new List<object>();
        //faz algumas verificações de possíveis erros
        if (ddOrganism.SelectedValue == "0")
        {
            HttpContext.Current.Session["exception"] = "NO ORGANISM FOUND!";
            Response.Redirect("../../../Visual/Errors/error.aspx");
        }
        else
        {
            String Organismid = ddOrganism.SelectedValue;
            DataSet ds = SequenceDAO.select("WHERE idorganism =" + Organismid + " AND status=0", "");
            if (ds.Tables[0].Rows.Count == 0)
            {
                HttpContext.Current.Session["exception"] = "No unmapped sequences found!";
                Response.Redirect("../../../Visual/Errors/error.aspx");
                return;
            }
            else
            {
                //obtém o id do dorganismo
                DataSet ds2 = ReferenceDAO.select("WHERE idorganism =" + Organismid, "");
                //obtém o id da sequência de referência(tabela sequences)
                String ReferenceSequenceid = Convert.ToString(ds2.Tables[0].Rows[0][1]);
                //obtém id da referência(tabela references)
                String idRefSeq = Convert.ToString(ds2.Tables[0].Rows[0][0]);
                //obtém a sequência de referência a partir do id obtido anteriormente
                DataSet ds3 = SequenceDAO.select("WHERE id=" + ReferenceSequenceid, "");
                //cria o objeto da sequência de referência
                Sequence referenceSequence = SequenceDAO.DStoList(ds3)[0];
                //Obtém o usuário que iniciou a ação
                VSDBM.Code.dto.User usuariologado = (VSDBM.Code.dto.User)HttpContext.Current.Session["usuariologado"];
                //instancia o objeto Jobid
                String JobId = "";
                //Cria Jobid diferenciado
                String codeprepair = usuariologado.name;
                codeprepair += Convert.ToString(ddOrganism.SelectedValue);
                codeprepair += Convert.ToString(new Random().Next());
                JobId = Encryption.CalculateMD5Hash(codeprepair);
                //insere os parâmetros na lista
                parametros.Add(ds);
                parametros.Add(referenceSequence);
                parametros.Add(idRefSeq);
                parametros.Add(JobId);
                parametros.Add(usuariologado);

                //prepara o ThreadStarter para iniciar a thread.
                ParameterizedThreadStart Starter = new ParameterizedThreadStart(threadMap);
                //Instancia a thread e aponta para o threadstarter.
                Thread MapThread = new Thread(Starter);
                //inicia a thread passando os parâmetros necessários.
                MapThread.Start(parametros);

                //armazena mensagem de "Done" na session do usuário.
                HttpContext.Current.Session["done"] = "Process started. <br> We will send you a message when it finishes. <br><br> Job Code: " + JobId + "<br>";
                //Redireciona o usuário para a página de "DONE"
                Response.Redirect("../../../Visual/Done/Done.aspx");
            }
        }
    }

    public void threadMap(object obj)
    {
        System.DateTime startTime = DateTime.Now;
        //instancia a lista de parametros
        List<object> list = obj as List<object>;
        //transforma os parametros em seus tipos de origem(casting)
        DataSet ds = list[0] as DataSet;
        Sequence refSequence = list[1] as Sequence;
        String idRefSeq = list[2] as String;
        String JobId = list[3] as String;
        User usuariologado = list[4] as User;
        //obtém lista de sequências do Dataset
        List<Sequence> seqlist = SequenceDAO.DStoList(ds);
        //Instancia a lista de resultado
        List<String[]> result = new List<string[]>();
        //cria lista de erros
        List<String[]> result2 = new List<string[]>();
        //cria a lista de Features da referência
        List<Reference_Feature> featurelist = Reference_FeatureDAO.DStoList(Reference_FeatureDAO.select("WHERE idseqref="+idRefSeq, ""));
        //instancia o vertor de erro
        String[] erros = new String[5];
        //instancia o vetor de resultado
        String[] resultado = new String[5];
        //inicia o contador de erros
        int errors =0;
        //inicia as interações de mapeamento
        foreach (Sequence sequence in seqlist)
        {
            
            
            try
            {
                //realiza o alinhamento com a referencia
                refSequence.sequence = refSequence.sequence.ToUpper().Replace("\r\n", "").Replace(" ", "");
                sequence.sequence = sequence.sequence.ToUpper().Replace("\r\n", "").Replace(" ", "");
                NeedlemanWunschMMF need = new NeedlemanWunschMMF(sequence.sequence.ToCharArray(),refSequence.sequence.ToCharArray());
                need.executar();
                String DatabaseWIndels = need.mAlignmentSeqA;
                Char[] vetor = DatabaseWIndels.ToCharArray();
                int inicial = 1;
                int final = 2;
               //arruma e conta os gaps
                for (int x = 0; x < vetor.Length; x++)
                {
                    if (vetor[x] != '-')
                    {
                        inicial = x + 1;
                        x = vetor.Length;
                    }
                }
                for (int y = vetor.Length - 1; y >= 0; y--)
                {
                    if (vetor[y] != '-')
                    {
                        final = y + 1;
                        y = -1;
                    }
                }
                //armazena o resultado
                resultado[0] = sequence.idacession;
                resultado[1] = need.mAlignmentSeqA + "\r\n" + need.mAlignmentSeqB;
                resultado[2] = Convert.ToString(need.mScore);
                resultado[3] = Convert.ToString(inicial);
                resultado[4] = Convert.ToString(final);

                //mapeia nas features a partir do alinhamento(identifica o intervalo e armazena o mapeamento)
                foreach (Reference_Feature feature in featurelist)
                {
                    Mapping map = new Mapping();
                    if (feature.positionInitial < final && feature.positionFinal > inicial)
                    {
                        if (feature.positionInitial >= inicial)
                        {
                            if (feature.positionFinal <= final)
                            {
                                map.idfeature = feature.id;
                                map.idsequence = sequence.id;
                                map.qualifier = "TOTAL";
                                map.posinitial = inicial;
                                map.posfinal = final;
                                MappingDAO.add(map);
                            }
                            else
                            {
                                map.idfeature = feature.id;
                                map.idsequence = sequence.id;
                                map.qualifier = "PARTIAL";
                                map.posinitial = inicial;
                                map.posfinal = final;
                                MappingDAO.add(map);
                            }
                        }
                        else 
                        {
                            map.idfeature = feature.id;
                            map.idsequence = sequence.id;
                            map.qualifier = "PARTIAL";
                            map.posinitial = inicial;
                            map.posfinal = final;
                            MappingDAO.add(map);
                        }
                    }
                }
               

            }
            catch (Exception e)
            {
                erros[0] = sequence.idacession;
                erros[1] = "ERRO";
                erros[2] = e.Message;
                result2.Add(erros);
                errors ++;
                continue;
            }
            result.Add(resultado);

        }
        //prepara a mensagem
        String elapsed = DateTime.Now.Subtract(startTime).ToString(@"hh\:mm\:ss\.FF");
        StringBuilder reportBuilder = new StringBuilder();
        reportBuilder.Append("Job Finished!");
        reportBuilder.Append(" \r\n");
        reportBuilder.Append("Time elapsed: "+ elapsed);
        reportBuilder.Append(" \r\n");
        reportBuilder.Append((seqlist.Count-errors).ToString() + " sequences mapped.");
        reportBuilder.Append(" \r\n");
        reportBuilder.Append(errors.ToString() + " errors where found.");
        reportBuilder.Append(" \r\n");
        if (errors > 0)
        {
            reportBuilder.Append("     ERROR REPORT     ");
            reportBuilder.Append(" \r\n");
            foreach(String[] erro in result2)
            {
                reportBuilder.Append("SEQUENCE ID: "+ erro[0] +" ERROR MESSAGE: "+erro[2]);
                reportBuilder.Append(" \r\n");
            }
        }
        //Envia mensagem com o report.
        Message msg = new Message();
        msg.senduserid = usuariologado.id;
        msg.touserid = usuariologado.id;
        msg.title = "Job: " + JobId;
        msg.message = reportBuilder.ToString();
        MessageDAO.sendMessage(msg);
    }
}